home *** CD-ROM | disk | FTP | other *** search
/ Super PC 34 / Super PC 34 (Shareware).iso / spc / UTIL / DJGPP2 / V2MISC / WMEMU2S.ZIP / LINUX / DRIVERS / FPU-EMU / GET_ADDR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-28  |  8.3 KB  |  323 lines

  1. /*---------------------------------------------------------------------------+
  2.  |  get_address.c                                                            |
  3.  |                                                                           |
  4.  | Get the effective address from an FPU instruction.                        |
  5.  |                                                                           |
  6.  | Copyright (C) 1992,1993,1994                                              |
  7.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  8.  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  9.  |                                                                           |
  10.  |                                                                           |
  11.  +---------------------------------------------------------------------------*/
  12.  
  13. /*---------------------------------------------------------------------------+
  14.  | Note:                                                                     |
  15.  |    The file contains code which accesses user memory.                     |
  16.  |    Emulator static data may change when user memory is accessed, due to   |
  17.  |    other processes using the emulator while swapping is in progress.      |
  18.  +---------------------------------------------------------------------------*/
  19.  
  20.  
  21. #include <linux/stddef.h>
  22.  
  23. #include <asm/segment.h>
  24.  
  25. #include "fpu_system.h"
  26. #include "exception.h"
  27. #include "fpu_emu.h"
  28.  
  29. static int reg_offset[] = {
  30.     offsetof(struct info,___eax),
  31.     offsetof(struct info,___ecx),
  32.     offsetof(struct info,___edx),
  33.     offsetof(struct info,___ebx),
  34.     offsetof(struct info,___esp),
  35.     offsetof(struct info,___ebp),
  36.     offsetof(struct info,___esi),
  37.     offsetof(struct info,___edi)
  38. };
  39.  
  40. #define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
  41.  
  42. static int reg_offset_vm86[] = {
  43.     offsetof(struct info,___cs),
  44.     offsetof(struct info,___vm86_ds),
  45.     offsetof(struct info,___vm86_es),
  46.     offsetof(struct info,___vm86_fs),
  47.     offsetof(struct info,___vm86_gs),
  48.     offsetof(struct info,___ss),
  49.     offsetof(struct info,___vm86_ds)
  50.       };
  51.  
  52. #define VM86_REG_(x) (*(unsigned short *) \
  53.               (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
  54.  
  55.  
  56. /* Decode the SIB byte. This function assumes mod != 0 */
  57. static void *sib(int mod, unsigned long *fpu_eip)
  58. {
  59.   unsigned char ss,index,base;
  60.   long offset;
  61.  
  62.   RE_ENTRANT_CHECK_OFF;
  63.   FPU_code_verify_area(1);
  64.   base = get_fs_byte((char *) (*fpu_eip));   /* The SIB byte */
  65.   RE_ENTRANT_CHECK_ON;
  66.   (*fpu_eip)++;
  67.   ss = base >> 6;
  68.   index = (base >> 3) & 7;
  69.   base &= 7;
  70.  
  71.   if ((mod == 0) && (base == 5))
  72.     offset = 0;              /* No base register */
  73.   else
  74.     offset = REG_(base);
  75.  
  76.   if (index == 4)
  77.     {
  78.       /* No index register */
  79.       /* A non-zero ss is illegal */
  80.       if ( ss )
  81.     EXCEPTION(EX_Invalid);
  82.     }
  83.   else
  84.     {
  85.       offset += (REG_(index)) << ss;
  86.     }
  87.  
  88.   if (mod == 1)
  89.     {
  90.       /* 8 bit signed displacement */
  91.       RE_ENTRANT_CHECK_OFF;
  92.       FPU_code_verify_area(1);
  93.       offset += (signed char) get_fs_byte((char *) (*fpu_eip));
  94.       RE_ENTRANT_CHECK_ON;
  95.       (*fpu_eip)++;
  96.     }
  97.   else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
  98.     {
  99.       /* 32 bit displacment */
  100.       RE_ENTRANT_CHECK_OFF;
  101.       FPU_code_verify_area(4);
  102.       offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
  103.       RE_ENTRANT_CHECK_ON;
  104.       (*fpu_eip) += 4;
  105.     }
  106.  
  107.   return (void *) offset;
  108. }
  109.  
  110.  
  111. static unsigned long vm86_segment(unsigned char segment)
  112.   segment--;
  113. #ifdef PARANOID
  114.   if ( segment > PREFIX_SS_ )
  115.     {
  116.       EXCEPTION(EX_INTERNAL|0x130);
  117.       math_abort(FPU_info,SIGSEGV);
  118.     }
  119. #endif PARANOID
  120.   return (unsigned long)VM86_REG_(segment) << 4;
  121. }
  122.  
  123.  
  124. /*
  125.        MOD R/M byte:  MOD == 3 has a special use for the FPU
  126.                       SIB byte used iff R/M = 100b
  127.  
  128.        7   6   5   4   3   2   1   0
  129.        .....   .........   .........
  130.         MOD    OPCODE(2)     R/M
  131.  
  132.  
  133.        SIB byte
  134.  
  135.        7   6   5   4   3   2   1   0
  136.        .....   .........   .........
  137.         SS      INDEX        BASE
  138.  
  139. */
  140.  
  141. void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
  142.          fpu_addr_modes addr_modes)
  143. {
  144.   unsigned char mod;
  145.   long *cpu_reg_ptr;
  146.   int offset = 0;     /* Initialized just to stop compiler warnings. */
  147.  
  148. #ifndef PECULIAR_486
  149.   /* This is a reasonable place to do this */
  150.   FPU_data_selector = FPU_DS;
  151. #endif PECULIAR_486
  152.  
  153.   /* Memory accessed via the cs selector is write protected
  154.      in 32 bit protected mode. */
  155. #define FPU_WRITE_BIT 0x10
  156.   if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
  157.       && (addr_modes.override.segment == PREFIX_CS_) )
  158.     {
  159.       math_abort(FPU_info,SIGSEGV);
  160.     }
  161.  
  162.   mod = (FPU_modrm >> 6) & 3;
  163.  
  164.   if (FPU_rm == 4 && mod != 3)
  165.     {
  166.       FPU_data_address = sib(mod, fpu_eip);
  167.       return;
  168.     }
  169.  
  170.   cpu_reg_ptr = & REG_(FPU_rm);
  171.   switch (mod)
  172.     {
  173.     case 0:
  174.       if (FPU_rm == 5)
  175.     {
  176.       /* Special case: disp32 */
  177.       RE_ENTRANT_CHECK_OFF;
  178.       FPU_code_verify_area(4);
  179.       offset = get_fs_long((unsigned long *) (*fpu_eip));
  180.       (*fpu_eip) += 4;
  181.       RE_ENTRANT_CHECK_ON;
  182.       FPU_data_address = (void *) offset;
  183.       return;
  184.     }
  185.       else
  186.     {
  187.       FPU_data_address = (void *)*cpu_reg_ptr;  /* Just return the contents
  188.                            of the cpu register */
  189.       return;
  190.     }
  191.     case 1:
  192.       /* 8 bit signed displacement */
  193.       RE_ENTRANT_CHECK_OFF;
  194.       FPU_code_verify_area(1);
  195.       offset = (signed char) get_fs_byte((char *) (*fpu_eip));
  196.       RE_ENTRANT_CHECK_ON;
  197.       (*fpu_eip)++;
  198.       break;
  199.     case 2:
  200.       /* 32 bit displacement */
  201.       RE_ENTRANT_CHECK_OFF;
  202.       FPU_code_verify_area(4);
  203.       offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
  204.       (*fpu_eip) += 4;
  205.       RE_ENTRANT_CHECK_ON;
  206.       break;
  207.     case 3:
  208.       /* Not legal for the FPU */
  209.       EXCEPTION(EX_Invalid);
  210.     }
  211.  
  212.   if ( addr_modes.vm86 )
  213.     {
  214.       offset += vm86_segment(addr_modes.override.segment);
  215.     }
  216.  
  217.   FPU_data_address = offset + (char *)*cpu_reg_ptr;
  218. }
  219.  
  220.  
  221. void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
  222.               fpu_addr_modes addr_modes)
  223. {
  224.   unsigned char mod;
  225.   int offset = 0;     /* Default used for mod == 0 */
  226.  
  227. #ifndef PECULIAR_486
  228.   /* This is a reasonable place to do this */
  229.   FPU_data_selector = FPU_DS;
  230. #endif PECULIAR_486
  231.  
  232.   /* Memory accessed via the cs selector is write protected
  233.      in 32 bit protected mode. */
  234. #define FPU_WRITE_BIT 0x10
  235.   if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
  236.       && (addr_modes.override.segment == PREFIX_CS_) )
  237.     {
  238.       math_abort(FPU_info,SIGSEGV);
  239.     }
  240.  
  241.   mod = (FPU_modrm >> 6) & 3;
  242.  
  243.   switch (mod)
  244.     {
  245.     case 0:
  246.       if (FPU_rm == 6)
  247.     {
  248.       /* Special case: disp16 */
  249.       RE_ENTRANT_CHECK_OFF;
  250.       FPU_code_verify_area(2);
  251.       offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
  252.       (*fpu_eip) += 2;
  253.       RE_ENTRANT_CHECK_ON;
  254.       goto add_segment;
  255.     }
  256.       break;
  257.     case 1:
  258.       /* 8 bit signed displacement */
  259.       RE_ENTRANT_CHECK_OFF;
  260.       FPU_code_verify_area(1);
  261.       offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
  262.       RE_ENTRANT_CHECK_ON;
  263.       (*fpu_eip)++;
  264.       break;
  265.     case 2:
  266.       /* 16 bit displacement */
  267.       RE_ENTRANT_CHECK_OFF;
  268.       FPU_code_verify_area(2);
  269.       offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
  270.       (*fpu_eip) += 2;
  271.       RE_ENTRANT_CHECK_ON;
  272.       break;
  273.     case 3:
  274.       /* Not legal for the FPU */
  275.       EXCEPTION(EX_Invalid);
  276.       break;
  277.     }
  278.   switch ( FPU_rm )
  279.     {
  280.     case 0:
  281.       offset += FPU_info->___ebx + FPU_info->___esi;
  282.       break;
  283.     case 1:
  284.       offset += FPU_info->___ebx + FPU_info->___edi;
  285.       break;
  286.     case 2:
  287.       offset += FPU_info->___ebp + FPU_info->___esi;
  288.       if ( addr_modes.override.segment == PREFIX_DEFAULT )
  289.     addr_modes.override.segment = PREFIX_SS_;
  290.       break;
  291.     case 3:
  292.       offset += FPU_info->___ebp + FPU_info->___edi;
  293.       if ( addr_modes.override.segment == PREFIX_DEFAULT )
  294.     addr_modes.override.segment = PREFIX_SS_;
  295.       break;
  296.     case 4:
  297.       offset += FPU_info->___esi;
  298.       break;
  299.     case 5:
  300.       offset += FPU_info->___edi;
  301.       break;
  302.     case 6:
  303.       offset += FPU_info->___ebp;
  304.       if ( addr_modes.override.segment == PREFIX_DEFAULT )
  305.     addr_modes.override.segment = PREFIX_SS_;
  306.       break;
  307.     case 7:
  308.       offset += FPU_info->___ebx;
  309.       break;
  310.     }
  311.  
  312.  add_segment:
  313.   offset &= 0xffff;
  314.  
  315.   if ( addr_modes.vm86 )
  316.     {
  317.       offset += vm86_segment(addr_modes.override.segment);
  318.     }
  319.  
  320.   FPU_data_address = (void *)offset ;
  321. }
  322.